package net.sf.rose.jdbc.query;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.rose.jdbc.ConstantCode;
import net.sf.rose.jdbc.bean.DbUserBean;
import net.sf.rose.jdbc.bean.FieldBean;
import net.sf.rose.jdbc.bean.ModelBean;
import net.sf.rose.jdbc.bean.TableBean;
import net.sf.rose.jdbc.service.Service;
import net.sf.rose.util.DateFormat;
import net.sf.rose.util.RoseRuntimeException;

/**
 * 类说明：自动拼接SQL语句
 * 
 * @author fengjian
 * @since 2013/05/18
 */
public class MapSQL extends QuerySQL {

	public MapSQL() {
		super();
	}

	public MapSQL(Service service) {
		super();
		super.service = service;
	}

	/**
	 * 功能:拼装SQL查询语句
	 * 
	 * @param map - 参数键值列表
	 */
	public void createSql(Map<String, Object> map) {
		getTableBean(map);
		StringBuilder buf = super.setSQL("SELECT * FROM ");
		buf.append(tableName);
		// 创建查询条件SQL语句
		String condition = this._createConditionSql(map);
		if (!condition.equals("")) {
			buf.append(" WHERE ");
			buf.append(condition);
		}
		// 添加查询机构过滤条件
		getDataAuthorFilter();
	}

	/**
	 * 功能:拼装SQL查询列表语句
	 * 
	 * @param sql  - SQL语句
	 * @param data - 参数对象
	 *             <p>
	 *             3.示例：表名：user
	 *             <p>
	 *             字段：userName 字符串；age 数字；birthday 日期；
	 *             <p>
	 *             String sql = "SELECT * FROM user where userName=#userName#";
	 *             <p>
	 *             Map<String, Object> data = new HashMap<>();
	 *             <p>
	 *             data.put("userName", "pingping");
	 *             <p>
	 *             MapDAO dao = new MapDAO(service);
	 *             <p>
	 *             MapSQL query = dao.getQuerySQL();
	 *             <p>
	 *             query.createSql(sql, data);
	 *             <p>
	 *             结果sql输出：select * from user where userName=?
	 *             <p>
	 *             结果查询参数："pingping"
	 */
	public void createSqlByMap(String sql, Map<String, Object> data) {
		String key = null;
		StringBuilder sb = super.setSQL(sql);
		int i = sb.indexOf("#");
		if (i == -1) {
			return;
		}
		int j = sb.indexOf("#", i + 1);
		do {
			key = sb.substring(i + 1, j);
			list.add(data.get(key));
			sb.replace(i, j + 1, "?");
			i = sb.indexOf("#");
			j = sb.indexOf("#", i + 1);
		} while (i != -1 && j != -1);
	}

	/**
	 * 功能:拼装SQL插入语句
	 * 
	 * @param map - 参数对象
	 */
	public void createSaveSql(Map<String, Object> map) {
		Map<String, Object> conMap = this.getConditionMap(map);
		// 如果没有条件，则是新增
		if (conMap.size() == 0) {
			createInsertSql(map);
		} else {
			createUpdateSql(map, conMap);
		}
	}

	/**
	 * 功能:拼装SQL插入语句
	 * 
	 * @param map - 参数对象
	 */
	public void createInsertSql(Map<String, Object> map) {
		TableBean table = this.getTableBean(map);
		// 给实体类添加默认数据，创建时间，更新时间，创建人，所在部门，所属机构
		Timestamp timestamp = DateFormat.getTimestamp();
		if (table.getFieldBeanByPropertyName(ModelBean.CREATE_TIME) != null) {
			map.put(ModelBean.CREATE_TIME, timestamp);
		}
		if (table.getFieldBeanByPropertyName(ModelBean.UPDATE_TIME) != null) {
			map.put(ModelBean.UPDATE_TIME, timestamp);
		}
		DbUserBean user = this.service.getUser();
		if (user != null) {
			if (table.getFieldBeanByPropertyName(ModelBean.CREATE_USER_ID) != null) {
				map.put(ModelBean.CREATE_USER_ID, user.getUserID());
				map.put(ModelBean.CREATE_USER_NAME, user.getUserName());
			}
			if (table.getFieldBeanByPropertyName(ModelBean.UPDATE_USER_ID) != null) {
				map.put(ModelBean.UPDATE_USER_ID, user.getUserID());
				map.put(ModelBean.UPDATE_USER_NAME, user.getUserName());
			}
			if (table.getFieldBeanByPropertyName(ModelBean.DEPART_ID) != null) {
				map.put(ModelBean.DEPART_ID, user.getDepartID());
			}
			if (table.getFieldBeanByPropertyName(ModelBean.ORG_ID) != null) {
				map.put(ModelBean.ORG_ID, user.getOrgID());
			}
		}
		FieldBean pk = table.getPkField();
		// 如果表有主键，而且主键值不存在
		if (pk != null && map.get(pk.getFieldName()) == null) {
			map.put(pk.getFieldName(), pk.uuid(map));
		}
		// 拼接SQL文
		list.clear();
		Object val = null;
		StringBuilder buf = new StringBuilder();
		StringBuilder valbuf = new StringBuilder();
		buf.append("INSERT INTO ");
		buf.append(table.getTableName());
		buf.append("(");

		valbuf.append("VALUES(");
		for (FieldBean field : table.getFields()) {
			// 如果不需要持久化
			if (!field.isPresist()) {
				continue;
			}
			// 将提交的字符串值转换成数据库的数据类型
			val = convertValue(field, map);
			buf.append(field.getFieldName()).append(",");
			valbuf.append("?,");
			list.add(val);
		}
		buf.replace(buf.length() - 1, buf.length(), ")");
		valbuf.replace(valbuf.length() - 1, valbuf.length(), ")");
		buf.append(valbuf);
		super.sql = buf;
	}

	/**
	 * 将字符串值转换成数据库定义的数据类型
	 * 
	 * @param field
	 * @param map
	 * @return
	 */
	private Object convertValue(FieldBean field, Map<String, Object> map) {
		Object val = map.get(field.getFieldName());
		if (val == null) {
			return val;
		}
		String type = field.getType();
		// 如果属性是字符串
		if (type.equals(ConstantCode.DATA_TYPE_FIX_STRING) || type.equals(ConstantCode.DATA_TYPE_VAR_STRING)
				|| type.equals(ConstantCode.DATA_TYPE_BIG_STRING)) {
			String str = val.toString().trim();
			if (str.equals("")) {
				return null;
			}
			return str;
		}
		// 如果属性是整型
		else if (type.equals(ConstantCode.DATA_TYPE_INT)) {
			String str = val.toString().trim();
			if (str.equals("")) {
				return 0;
			}
			val = Integer.parseInt(str);
		}
		// 如果属性是日期时间
		else if (type.equals(ConstantCode.DATA_TYPE_DATE)) {
			String str = val.toString().trim();
			if (str.equals("")) {
				return null;
			}
			DateFormat df = new DateFormat();
			val = df.format(str);
		}
		// 如果属性是数字长整型
		else if (type.equals(ConstantCode.DATA_TYPE_LONG)) {
			String str = val.toString().trim();
			if (str.equals("")) {
				return 0;
			}
			val = Long.parseLong(str);
		}
		// 如果属性是数字双精度型
		else if (type.equals(ConstantCode.DATA_TYPE_DOUBLE)) {
			String str = val.toString().trim();
			if (str.equals("")) {
				return 0;
			}
			val = Double.parseDouble(str);
		}
		// 如果属性是数字高精度型
		else if (type.equals(ConstantCode.DATA_TYPE_DECIMAL)) {
			String str = val.toString().trim();
			if (str.equals("")) {
				return 0;
			}
			val = new BigDecimal(str);
		}
		// 如果属性是数字列表或文本列表
		else if (type.equals(ConstantCode.DATA_TYPE_INT_LIST) || type.equals(ConstantCode.DATA_TYPE_STRING_LIST)) {
			if (val instanceof String[]) {
				String[] arr = (String[]) val;
				StringBuilder sb = new StringBuilder();
				for (int i = 0; i < arr.length; i++) {
					sb.append(arr[i]).append(",");
				}
				val = sb.substring(0, sb.length() - 1);
			} else {
				String str = val.toString().trim();
				if (str.equals("")) {
					return null;
				}
				val = str;
			}
		}
		return val;
	}

	/**
	 * 功能:拼装SQL更新语句
	 * 
	 * @param map - 参数容器
	 */
	public void createUpdateSql(Map<String, Object> map) {
		Map<String, Object> conMap = this.getConditionMap(map);
		if (conMap.size() == 0) {
			throw new RoseRuntimeException("不允许更新整个表的数据，更新SQL语句没有任何条件！");
		} else {
			createUpdateSql(map, conMap);
		}
	}

	/**
	 * 功能:拼装SQL更新语句
	 * 
	 * @param map       - 参数容器
	 * @param condition - 条件参数
	 *                  例：更新条件的数据库字段名是userName，那么条件字段名是userName_，条件类型名是userName_like
	 */
	public void createUpdateSql(Map<String, Object> map, Map<String, Object> condition) {
		// 找出所有需要强制更新的字段
		Map<String, String> forceUpdateMap = new HashMap<>();
		for (String key : map.keySet()) {
			if (key.endsWith("_forceUpdate")) {
				key = key.substring(0, key.length() - 12);
				forceUpdateMap.put(key, key);
			}
		}
		// 检查要操作的数据库表名是否已经指定
		TableBean table = this.getTableBean(map);
		// 如果数据库表中有更新人字段
		if (table.getFieldBeanByFieldName(ModelBean.UPDATE_USER_ID) != null
				&& map.get(ModelBean.UPDATE_USER_ID) == null) {
			DbUserBean user = this.service.getUser();
			if (user != null) {
				map.put(ModelBean.UPDATE_USER_ID, user.getUserID());
				map.put(ModelBean.UPDATE_USER_NAME, user.getUserName());
			}
		}
		// 如果数据库表中有更新时间字段
		if (table.getFieldBeanByFieldName(ModelBean.UPDATE_TIME) != null && map.get(ModelBean.UPDATE_TIME) == null) {
			map.put(ModelBean.UPDATE_TIME, DateFormat.getTimestamp());
		}
		StringBuilder buf = new StringBuilder();
		buf.append("UPDATE ");
		buf.append(table.getTableName());
		buf.append(" SET ");

		list.clear();
		for (FieldBean field : table.getFields()) {
			// 如果不需要持久化
			if (!field.isPresist()) {
				continue;
			}
			String type = field.getType();
			Object val = map.get(field.getFieldName());
			Object force = map.get(field.getFieldName() + "_forceUpdate");
			// 如果属性是字符串
			if (type.equals(ConstantCode.DATA_TYPE_FIX_STRING) || type.equals(ConstantCode.DATA_TYPE_VAR_STRING)
					|| type.equals(ConstantCode.DATA_TYPE_BIG_STRING)) {
				if (val == null) {
					// 如果不需要强制更新
					if (force == null) {
						continue;
					}
				} else {
					String str = val.toString().trim();
					if (str.equals("")) {
						// 如果不需要强制更新
						if (force == null) {
							continue;
						}
					} else {
						val = str;
					}
				}
			}
			// 如果属性是整型
			else if (type.equals(ConstantCode.DATA_TYPE_INT)) {
				if (val == null) {
					continue;
				} else {
					val = Integer.parseInt(val.toString().trim());
				}
			}
			// 如果属性是日期时间
			else if (type.equals(ConstantCode.DATA_TYPE_DATE)) {
				if (val == null) {
					// 如果不需要强制更新
					if (force == null) {
						continue;
					}
				} else {
					String str = val.toString().trim();
					if (str.equals("")) {
						continue;
					}
					DateFormat df = new DateFormat();
					val = df.format(str);
				}
			}
			// 如果属性是数字长整型
			else if (type.equals(ConstantCode.DATA_TYPE_LONG)) {
				if (val == null) {
					continue;
				} else {
					val = Long.parseLong(val.toString().trim());
				}
			}
			// 如果属性是数字双精度型
			else if (type.equals(ConstantCode.DATA_TYPE_DOUBLE)) {
				if (val == null) {
					continue;
				} else {
					val = Double.parseDouble(val.toString().trim());
				}
			}
			// 如果属性是数字高精度型
			else if (type.equals(ConstantCode.DATA_TYPE_DECIMAL)) {
				if (val == null) {
					continue;
				} else {
					val = new BigDecimal(val.toString().trim());
				}
			}
			// 如果属性是数字列表
			else if (type.equals(ConstantCode.DATA_TYPE_INT_LIST)) {
				if (val == null) {
					continue;
				} else if (val instanceof String) {
					String str = val.toString().trim();
					if (str.equals("")) {
						// 如果不需要强制更新
						if (force == null) {
							continue;
						} else {
							val = null;
						}
					} else {
						val = str;
					}
				} else if (val instanceof int[]) {
					int[] arr = (int[]) val;
					StringBuilder sb = new StringBuilder();
					for (int i = 0; i < arr.length; i++) {
						sb.append(arr[i]).append(",");
					}
					val = sb.substring(0, sb.length() - 1);
				}
			}
			// 如果属性是文本列表
			else if (type.equals(ConstantCode.DATA_TYPE_STRING_LIST)) {
				if (val == null) {
					continue;
				} else if (val instanceof String) {
					String str = val.toString().trim();
					if (str.equals("")) {
						// 如果不需要强制更新
						if (force == null) {
							continue;
						} else {
							val = null;
						}
					} else {
						val = str;
					}
				} else if (val instanceof String[]) {
					String[] arr = (String[]) val;
					StringBuilder sb = new StringBuilder();
					for (int i = 0; i < arr.length; i++) {
						sb.append(arr[i]).append(",");
					}
					val = sb.substring(0, sb.length() - 1);
				}
			}
			buf.append(field.getFieldName()).append("=?, ");
			list.add(val);
		}
		// 拼接SQL条件语句
		buf.deleteCharAt(buf.length() - 2);
		String con = this._createConditionSql(condition);
		if (!con.equals("")) {
			buf.append(" WHERE ");
			buf.append(con);
		}
		super.sql = buf;
	}

	/**
	 * 功能:拼装SQL删除语句
	 * 
	 * @param map - 返回对象类型
	 */
	public void createDeleteSql(Map<String, Object> map) {
		// 检查要操作的数据库表名是否已经指定
		this.getTableBean(map);
		list.clear();
		StringBuilder buf = new StringBuilder();
		buf.append("DELETE FROM ");
		buf.append(tableName);
		String condition = this._createConditionSql(map);
		if (!condition.equals("")) {
			buf.append(" WHERE ");
			buf.append(condition);
		}
		super.sql = buf;
	}

	/**
	 * 功能：检查要操作的数据库表名是否已经指定
	 * 
	 * @param map - 参数容器
	 * @return 数据库表定义元数据类
	 */
	private TableBean getTableBean(Map<String, Object> map) {
		Object obj = map.remove("tableName");
		if (obj == null) {
			if (tableName == null) {
				throw new RoseRuntimeException("必须要的查询参数：表或视图名必须提供，否则不能拼接SQL文!");
			}
		} else {
			tableName = obj.toString();
		}
		TableBean tableBean = Service.getTableBean(tableName);
		if (tableBean == null) {
			throw new RoseRuntimeException("表或视图名称：" + tableName + "在数据库中不存在！");
		}
		return tableBean;
	}

	/**
	 * 功能：从请求参数中找出所有数据库条件
	 * 
	 * @param map - 请求参数容器
	 * @return
	 */
	private Map<String, Object> getConditionMap(Map<String, Object> map) {
		Map<String, Object> data = new HashMap<>();
		for (String key : map.keySet()) {
			if (key.charAt(0) == '_') {
				data.put(key.substring(1), map.get(key));
			}
		}
		data.remove("token");
		return data;
	}

	/**
	 * 返回从Map中获取字段的名称 BeanSQL用的是propertyName，MapSQL用的是fieldName
	 * 
	 * @param field 字段定义
	 * @return 返回数据库字段名称
	 */
	@Override
	public String getConditionKey(FieldBean field) {
		return field.getPropertyName();
	}

	/**
	 * 功能:拼装批处理插入SQL语句
	 * 
	 * @param beans - 类对象列表
	 */
	@SuppressWarnings("unchecked")
	public void createBatchInsertSql(List<?> beans) {
		String key = null;
		list.clear();
		TableBean table = super.getTableBean();
		List<FieldBean> fields = table.getFields();
		// 拼接SQL文
		StringBuilder sb = new StringBuilder();
		StringBuilder st = new StringBuilder();
		sb.append("insert into ").append(table.getTableName()).append('(');
		st.append("values(");
		List<String> keys = new ArrayList<>();
		FieldBean pk = null;
		for (FieldBean f : fields) {
			// 如果不需要持久化
			if (!f.isPresist()) {
				continue;
			}
			if (f.isPk()) {
				pk = table.getPkField();
			} else {
				key = f.getFieldName();
				sb.append(key).append(',');
				st.append("?,");
				keys.add(f.getPropertyName());
			}
		}
		if (pk != null) {
			sb.append(pk.getFieldName()).append(")");
			st.append("?)");
			keys.add(pk.getPropertyName());
		} else {
			sb.deleteCharAt(sb.length() - 1);
			sb.append(')');
			st.deleteCharAt(st.length() - 1);
			st.append(')');
		}
		sb.append(st.toString());
		super.sql = sb;
		// 准备参数列表
		int size = keys.size();
		DbUserBean user = this.service.getUser();
		Timestamp timestamp = DateFormat.getTimestamp();
		for (int k = 0; k < beans.size(); k++) {
			Map<String, Object> map = (Map<String, Object>) beans.get(k);
			map.put(ModelBean.CREATE_TIME, timestamp);
			map.put(ModelBean.UPDATE_TIME, timestamp);
			if (user != null) {
				map.put(ModelBean.ORG_ID, user.getOrgID());
				map.put(ModelBean.DEPART_ID, user.getDepartID());
				map.put(ModelBean.CREATE_USER_ID, user.getUserID());
				map.put(ModelBean.CREATE_USER_NAME, user.getUserName());
				map.put(ModelBean.UPDATE_USER_ID, user.getUserID());
				map.put(ModelBean.UPDATE_USER_NAME, user.getUserName());
			}
			Object[] arr = new Object[size];
			for (int i = 0; i < size; i++) {
				arr[i] = map.get(keys.get(i));
			}
			if (pk != null) {
				// 如果主键不存在
				if (arr[size - 1] == null || arr[size - 1].toString().equals("0")) {
					arr[size - 1] = pk.getBeanKeyGenerator().uuid(beans.get(k));
				}
			}
			super.list.add(arr);
		}
		super.sql = sb;
	}
}
